import re
import unittest
from datetime import datetime, date


class ValidationError(Exception):
    pass


class Field():
    def __init__(self, default=None, blank=False):
        self.default = default
        self.blank = blank

    def __eq__(self, other):
        return self.default == other

    def validate(self):
        pass


class CharField(Field):
    def __init__(self, max_length=None, min_length=0, default=None, blank=False):
        Field.__init__(self, default, blank)
        self.min_length = min_length
        self.max_length = max_length

    def validate(self):
        value = self.default
        if type(value) is not str:
            raise ValidationError('type error','type dismatch')
        elif len(value) > self.max_length or len(value) < self.min_length:
            raise ValidationError('length error','')


class IntegerField(Field):
    def __init__(self, min_value=None, max_value=None, default=None, blank=False):
        Field.__init__(self, default, blank)
        self.min_value = min_value
        self.max_value = max_value

    def validate(self):
        value = self.default if self.default else 0
        if value > self.max_value or value < self.min_value:
            raise ValidationError('out of range','')


class BooleanField(Field):
    def __init__(self, default=None, blank=False):
        Field.__init__(self, default, blank)

    def validate(self):
        pass


class DateTimeField(Field):
    def __init__(self, auto_now=False, default=None, blank=False):
        Field.__init__(self, datetime.now()
                       if auto_now and not default else default, blank)
        self.auto_now = auto_now

    def __getattribute__(self, item):
        if item == 'default' and object.__getattribute__(self, 'auto_now') is True:
            return datetime.now()
        else:
            return object.__getattribute__(self, item)

    def validate(self):
        if type(self.default) is not datetime:
            raise ValidationError('type error','')


class EmailField(Field):
    def __init__(self, min_length=0, max_length=None, default=None, blank=False):
        Field.__init__(self, default, blank)
        self.min_length = min_length
        self.max_length = max_length

    def validate(self):
        if type(self.default) is not str:
            raise ValidationError('type error','')
        elif len(self.default) > self.max_length or len(self.default) < self.min_length:
            raise ValidationError('length error','')
        elif not re.match(r'[a-z]+@[a-z]+\.[a-z]+', self.default, re.I):
            raise ValidationError('invalid email','')
class ModelMeta(type):
    def __new__(meta, class_name, bases, class_dict):
        new_class_dict = {}

        for attribute_name, attribute in class_dict.items():
            if not isinstance(attribute, Field):
                new_class_dict[attribute_name] = attribute
                continue
            attribute.name = attribute_name
            new_class_dict.setdefault('_attributes_', {}).setdefault(attribute_name, attribute)

        return super(ModelMeta, meta).__new__(meta, class_name, bases, new_class_dict)


class Model(metaclass=ModelMeta):
    _attributes_ = {}

    def __init__(self, **kwds):
        for attr in self._attributes_.values():
            setattr(self, attr.name, kwds.get(attr.name, attr.default))

    def validate(self):
        for attr in self._attributes_.values():
            attr.validate(getattr(self, attr.name))
